package com.ayf.payment.game.api.task.alipay;

import com.ayf.payment.game.api.channel.alipay.service.AliPayService;
import com.ayf.payment.game.api.dto.alipay.AliOrderResult;
import com.ayf.payment.game.api.dto.alipay.AliOrderStatus;
import com.ayf.payment.game.api.dto.alipay.MerchantAlipayOrderDTO;
import com.ayf.payment.game.api.dto.criteria.MerchantAlipayOrderCriteria;
import com.ayf.payment.game.api.service.MerchantAlipayOrderService;
import com.ayf.payment.game.api.utils.SnowFlakeUtils;
import com.github.pagehelper.PageHelper;
import com.swwx.charm.commons.lang.utils.LogPortal;
import com.swwx.charm.zookeeper.exception.GetLockFailedException;
import com.swwx.charm.zookeeper.exception.ReleaseLockFailedException;
import com.swwx.charm.zookeeper.lock.DistributedLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;


@Component
public abstract class MerchantAliPayOrderCreatTaskImpl {

    // 每次处理的条数
    private final static int pageSize = 200;

    @Autowired
    private MerchantAlipayOrderService merchantAlipayOrderService;
    @Autowired
    private AliPayService aliPayService;

    protected void run(DistributedLock distributedLock) {
        boolean lock = false;
        String traceId = SnowFlakeUtils.getTraceId();
        String lockName = this.getClass().getSimpleName().concat(System.getenv("XY_GAME_PAY_LOCK_FLAG"));
        try {
            if (lock = distributedLock.getLock(lockName)) {
                LogPortal.info("{} >>> get lock and run {} ", traceId, lockName);

                MerchantAlipayOrderCriteria criteria = new MerchantAlipayOrderCriteria();
                criteria.setStatus(AliOrderStatus.CREAT.getCode());
                criteria.setOrderSource(1);
                PageHelper.startPage(1, pageSize);
                final List<MerchantAlipayOrderDTO> list = merchantAlipayOrderService.list(criteria);
                LogPortal.info("{} >>> [{}]处理总条数[{}]", traceId, lockName, list.size());
                if (list.size() <= 0) {
                    return;
                }
                //初始化信号
                final CountDownLatch countDownLatch = new CountDownLatch(list.size());
                for (int i = 0; i < list.size(); i++) {
                    MerchantAlipayOrderDTO dto = list.get(i);
                    int finalI = i + 1;
                    submit(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                LogPortal.info("{} >>> {} 商户支付宝代付-开始处理代付款中的第[{}]条记录", traceId, lockName, finalI);
                                Map<String, Object> map = aliPayService.balanceQuery(traceId, dto.getMerchantId(), dto.getMerchantOrderNo());
                                if ("1".equals(map.get("status"))){
                                    BigDecimal balance = (BigDecimal) map.get("balance");
                                    if (dto.getTransAmount().compareTo(balance) > 0) {
                                        AliOrderResult aliOrderResult = new AliOrderResult();
                                        aliOrderResult.setMerchantOrderNo(dto.getMerchantOrderNo());
                                        aliOrderResult.setStatus(AliOrderStatus.FAIL.getCode());
                                        aliOrderResult.setApplyTime(new Date());
                                        aliOrderResult.setAppId(String.valueOf(map.get("appId")));
                                        aliOrderResult.setFailReason("支付宝账号余额不足，余额为：" + balance + "元");
                                        aliOrderResult.setApplyTime(new Date());
                                        merchantAlipayOrderService.updateOrderStatus(aliOrderResult);
                                        LogPortal.info("{} >>> {} 商户支付宝代付-代付款中的第[{}]条记录处理完成-处理为失败-余额不足", traceId, lockName, finalI);
                                        return;
                                    }
                                } else {
                                    AliOrderResult aliOrderResult = new AliOrderResult();
                                    aliOrderResult.setMerchantOrderNo(dto.getMerchantOrderNo());
                                    aliOrderResult.setStatus(AliOrderStatus.FAIL.getCode());
                                    aliOrderResult.setApplyTime(new Date());
                                    aliOrderResult.setAppId(String.valueOf(map.get("appId")));
                                    aliOrderResult.setFailReason(String.valueOf(map.get("msg")));
                                    aliOrderResult.setApplyTime(new Date());
                                    merchantAlipayOrderService.updateOrderStatus(aliOrderResult);
                                    return;
                                }
                                aliPayService.orderCreate(dto);
                                LogPortal.info("{} >>> {} 商户支付宝代付-代付款中的第[{}]条记录处理完成", traceId, lockName, finalI);
                            } catch (Exception e) {
                                LogPortal.error("{} 商户ID[{}] 商户订单号[{}] 订单创建发生了{}异常，错误描述:{}",e,traceId, dto.getMerchantId(), dto.getMerchantOrderNo(), e.getClass().getSimpleName(), e.getMessage());
                            } finally {
                                //线程执行完成之后标记信号表示完成
                                countDownLatch.countDown();
                            }
                        }
                    });
                }
                //等待线程池任务执行完毕
                countDownLatch.await();
            } else {
                LogPortal.info("{} >>> {} do not get lock ", traceId, lockName);
            }
        } catch (
                GetLockFailedException e) {
            LogPortal.error("{} >>> [DISTRIBUTED_LOCK_ACQUIRE_FAILED_ZK] 分布式锁获取失败,锁名称为:{}", traceId, lockName);
            LogPortal.error("{} >>> {} 获取lock失败", e, traceId, lockName);
        } catch (
                Exception e) {
            LogPortal.error("{} >>> {} 任务执行出错 ", e, traceId, lockName);
        } finally {
            if (lock) {
                LogPortal.info(traceId + " >>> " + lockName + " finished.");
                try {
                    distributedLock.releaseLock(lockName);
                } catch (ReleaseLockFailedException e) {
                    LogPortal.error("{} >>> [DISTRIBUTED_LOCK_RELEASE_FAILED_ZK] 分布式锁释放失败,锁名称为:{}", traceId, lockName);
                    LogPortal.error("{} >>> {} 释放失败", e, traceId, lockName);
                }
            }
        }

    }

    protected abstract void submit(Runnable task);
}
